package com.ecommerce.service;

import com.ecommerce.dao.mybatis.mapper.ProductMapper;
import com.ecommerce.dto.ProductPageResultDTO;
import com.ecommerce.product.domain.IndexNameResolver;
import com.ecommerce.product.domain.Product;
import com.ecommerce.product.domain.ProductDocument;
import com.ecommerce.product.enums.ProductType;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 商品查询服务，
 * 负责商品查询逻辑的实现，
 * 此类在查询ES库时使用 Spring Data Elasticsearch (elasticsearchRestTemplate，Spring Data 封装)，
 * 而不是 Elasticsearch Java Client (RestHighLevelClient，底层原生API)
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ProductPageQueryOrdinaryService {

    /**
     * MyBatis商品Mapper，用于MySQL数据库操作
     */
    private final ProductMapper productMapper;

    /**
     * Elasticsearch操作模板，用于执行ES查询
     */
    private final ElasticsearchRestTemplate elasticsearchRestTemplate;

    /**
     * 索引名称解析器，用于根据商品类型解析索引名
     */
    private final IndexNameResolver indexNameResolver;

    /**
     * 是否启用Elasticsearch查询
     * 默认值从配置文件中读取，可动态修改
     */
    @Setter
    @Value("${app.product.es-enabled:true}")
    private boolean esEnabled;

    /**
     * ES查询失败时是否降级到MySQL
     * 默认值从配置文件中读取，可动态修改
     */
    @Setter
    @Value("${app.product.fallback-to-mysql:true}")
    private boolean fallbackToMysql;

    /**
     * 查询商品详情
     * @param id 商品ID
     * @return 商品详情对象
     */
    public Product getProductDetail(Long id) {
        return productMapper.selectById(id);
    }

    /**
     * 按分类分页查询商品，使用普通方式查询，未使用PIT
     * @param categoryId 一级分类ID
     * @param subCategoryId 二级分类ID
     * @param productType 商品类型
     * @param page 页码（从0开始）
     * @param size 每页大小
     * @return 分页查询结果DTO
     */
    public ProductPageResultDTO queryByCategory(Long categoryId, Long subCategoryId,
                                                ProductType productType, int page, int size) {
        if (esEnabled) {
            try {
                return queryByCategoryFromES(categoryId, subCategoryId, productType, page, size);
            } catch (Exception e) {
                log.error("ES查询失败，降级到MySQL", e);
                if (fallbackToMysql) {
                    return queryByCategoryFromMySQL(categoryId, subCategoryId, page, size);
                }
                throw new RuntimeException("商品查询服务异常");
            }
        }
        return queryByCategoryFromMySQL(categoryId, subCategoryId, page, size);
    }

    /**
     * 从Elasticsearch按分类查询商品
     *
     * @param categoryId    一级分类ID
     * @param subCategoryId 二级分类ID
     * @param productType   商品类型（用于确定索引）
     * @param page          页码（从0开始）
     * @param size          每页大小
     * @return 商品查询结果DTO
     */
    private ProductPageResultDTO queryByCategoryFromES(Long categoryId, Long subCategoryId,
                                                       ProductType productType, int page, int size) {
        // 1. 构建索引名
        String indexName = indexNameResolver.resolveIndexName(productType);
        IndexCoordinates index = IndexCoordinates.of(indexName);

        // 2. 构建查询条件
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery()
                .must(QueryBuilders.termQuery("status", 1));

        Optional.ofNullable(categoryId)
                .ifPresent(id -> boolQuery.must(QueryBuilders.termQuery("categoryId", id)));

        Optional.ofNullable(subCategoryId)
                .ifPresent(id -> boolQuery.must(QueryBuilders.termQuery("subCategoryId", id)));

        // 3. 构建排序条件（使用新版API）
        FieldSortBuilder sortBuilder = SortBuilders.fieldSort("createTime")
                .order(SortOrder.DESC);

        // 4. 构建查询（兼容Elasticsearch 7.16.2）
        NativeSearchQuery query = new NativeSearchQueryBuilder()
                .withQuery(boolQuery)
                .withSorts(sortBuilder) // 使用withSorts替代废弃的withSort
                .withPageable(PageRequest.of(page, size))
                .build();

        // 5. 执行查询
        SearchHits<ProductDocument> hits = elasticsearchRestTemplate.search(
                query, ProductDocument.class, index);

        // 6. 转换结果
        List<Product> products = hits.stream()
                .map(hit -> convertToProduct(hit.getContent()))
                .collect(Collectors.toList());

        // 7. 构建返回结果
        return ProductPageResultDTO.builder()
                .products(products)
                .totalCount(hits.getTotalHits())
                .currentPage(page)
                .pageSize(size)
                .build();
    }

    /**
     * 从MySQL按分类查询商品
     * @param categoryId 一级分类ID
     * @param subCategoryId 二级分类ID
     * @param page 页码
     * @param size 每页大小
     * @return 分页查询结果DTO
     */
    private ProductPageResultDTO queryByCategoryFromMySQL(Long categoryId, Long subCategoryId,
                                                          int page, int size) {
        List<Product> products = productMapper.selectByCategoryWithPage(
                categoryId, subCategoryId, page * size, size);

        long totalCount = productMapper.countByCategory(categoryId, subCategoryId);

        return ProductPageResultDTO.builder()
                .products(products)
                .totalCount(totalCount)
                .currentPage(page)
                .pageSize(size)
                .build();
    }

    /**
     * 商品分页搜索，使用普通方式查询，未使用PIT
     * @param keyword 搜索关键词
     * @param productType 商品类型
     * @param page 页码
     * @param size 每页大小
     * @return 分页搜索结果DTO
     */
    public ProductPageResultDTO search(String keyword, ProductType productType, int page, int size) {
        if (esEnabled) {
            try {
                return searchFromES(keyword, productType, page, size);
            } catch (Exception e) {
                log.error("ES搜索失败，降级到MySQL", e);
                if (fallbackToMysql) {
                    return searchFromMySQL(keyword, page, size);
                }
                throw new RuntimeException("商品搜索服务异常");
            }
        }
        return searchFromMySQL(keyword, page, size);
    }

    /**
     * 从ES搜索商品
     * @param keyword 搜索关键词
     * @param productType 商品类型
     * @param page 页码
     * @param size 每页大小
     * @return 分页搜索结果DTO
     */
    private ProductPageResultDTO searchFromES(String keyword, ProductType productType,
                                              int page, int size) {
        String indexName = indexNameResolver.resolveIndexName(productType);
        IndexCoordinates index = IndexCoordinates.of(indexName);

        NativeSearchQuery query = new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.multiMatchQuery(keyword,
                        "name^3", "description^1", "categoryName^2", "subCategoryName^2"))
                .withPageable(PageRequest.of(page, size))
                .build();

        SearchHits<ProductDocument> hits = elasticsearchRestTemplate.search(
                query, ProductDocument.class, index);

        List<Product> products = hits.stream()
                .map(hit -> convertToProduct(hit.getContent()))
                .collect(Collectors.toList());

        return ProductPageResultDTO.builder()
                .products(products)
                .totalCount(hits.getTotalHits())
                .currentPage(page)
                .pageSize(size)
                .build();
    }

    /**
     * 从MySQL搜索商品
     * @param keyword 搜索关键词
     * @param page 页码
     * @param size 每页大小
     * @return 分页搜索结果DTO
     */
    private ProductPageResultDTO searchFromMySQL(String keyword, int page, int size) {
        List<Product> products = productMapper.searchByNameWithPage(keyword, page * size, size);
        long totalCount = productMapper.countByName(keyword);

        return ProductPageResultDTO.builder()
                .products(products)
                .totalCount(totalCount)
                .currentPage(page)
                .pageSize(size)
                .build();
    }

    /**
     * 转换ES文档为领域对象
     * @param doc ES文档对象
     * @return 商品领域对象
     */
    private Product convertToProduct(ProductDocument doc) {
        Product product = new Product();
        product.setId(doc.getId());
        product.setName(doc.getName());
        product.setPrice(doc.getPrice());
        // 其他字段转换...
        return product;
    }
}